/****************************************************************************
 *
 * Copyright (C) 2003-2008 Los Alamos National Security, LLC
 *                         Packet Analytics Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 2 as
 * published by the Free Software Foundation.  You may not use, modify or
 * distribute this program under any other version of the GNU General
 * Public License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 ****************************************************************************/
package nfse.dataset.netflow;

import java.sql.*;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.StringTokenizer;

import nfse.NetFSERecord;
import nfse.NetFSEUtil;
import nfse.dataset.session.Session;
import nfse.gui.record.FlexRecord;
import nfse.gui.record.FlexRecordField;

/*******************************************************************************
 * This class extends the Session class to parse and store LFAP records.
 * 
 * @author uphoff
 * 
 */
public class NetflowFlowToolsRecord extends Session {

    public static final int NUM_FIELDS_V1 = 12;

    public static final int NUM_FIELDS_V2 = 15;

    public int version = 1;

    /***************************************************************************
     * The router IP that generated this flow record
     */
    public String router = "0.0.0.0";

    public int tos = 0;

    public int tcpFlags = 0;

    /***************************************************************************
     * Parse a LFAP record into a LFAPRecord data structure.
     * 
     * @param line
     *            The tab-delimitted LFAP record
     * @return The parsed LFAP record data structure
     */
    public NetFSERecord generate(String line, int sensor) throws Exception {
        
            //System.out.println(line);
            //System.out.println(NetForSEUtil.convertFromHex(line));
            if (version == 2) {
                return generateV2(line, sensor);
            }

            NetflowFlowToolsRecord l = new NetflowFlowToolsRecord();
            l.version = 1;
            l.setInitialString(line);
            l.sensor = sensor;
            String[] tokens = null;
            StringTokenizer st = new StringTokenizer(line);
            tokens = new String[st.countTokens()];
            for (int i = 0; i < tokens.length; i++)
                tokens[i] = st.nextToken();
            // if (tokens.length != NUM_FIELDS) {
            // throw(new Exception("Invalid number of tokens: " +
            // tokens.length));
            // }

            String start = tokens[0]; // Example: 1026.22:42:20.621
            String stop = tokens[1];

            String[] startTokens = start.split("\\.");
            String[] startTimeTokens = startTokens[1].split(":");

            String[] stopTokens = stop.split("\\.");
            String[] stopTimeTokens = stopTokens[1].split(":");

            GregorianCalendar cal = new GregorianCalendar();
            int year = cal.get(Calendar.YEAR);
            int month = Integer.parseInt(startTokens[0].substring(0, 2));
            int day = Integer.parseInt(startTokens[0].substring(2, 4));
            int hour = Integer.parseInt(startTimeTokens[0]);
            int minute = Integer.parseInt(startTimeTokens[1]);
            int second = Integer.parseInt(startTimeTokens[2]);
            int millis = Integer.parseInt(startTokens[2]);
            year = 2005;
            cal.set(Calendar.YEAR, year);
            cal.set(Calendar.MONTH, month - 1);
            cal.set(Calendar.DAY_OF_MONTH, day);
            cal.set(Calendar.HOUR_OF_DAY, hour);
            cal.set(Calendar.MINUTE, minute);
            cal.set(Calendar.SECOND, second);
            cal.set(Calendar.MILLISECOND, millis);

            l.setStartTS(new Timestamp(cal.getTime().getTime()));

            year = 2005;
            month = Integer.parseInt(stopTokens[0].substring(0, 2));
            day = Integer.parseInt(stopTokens[0].substring(2, 4));
            hour = Integer.parseInt(stopTimeTokens[0]);
            minute = Integer.parseInt(stopTimeTokens[1]);
            second = Integer.parseInt(stopTimeTokens[2]);
            millis = Integer.parseInt(stopTokens[2]);
            cal.set(Calendar.YEAR, year);
            cal.set(Calendar.MONTH, month - 1);
            cal.set(Calendar.DAY_OF_MONTH, day);
            cal.set(Calendar.HOUR_OF_DAY, hour);
            cal.set(Calendar.MINUTE, minute);
            cal.set(Calendar.SECOND, second);
            cal.set(Calendar.MILLISECOND, millis);

            l.setEndTS(new Timestamp(cal.getTime().getTime()));

            l.setSrcIP(NetFSEUtil.convertIPtoLong(tokens[3]));
            l.setDstIP(NetFSEUtil.convertIPtoLong(tokens[6]));                
            
            l.srcPort = Integer.parseInt(tokens[4]);
            l.dstPort = Integer.parseInt(tokens[7]);
            l.srcPkts = Long.parseLong(tokens[10]);
            l.srcBytes = Long.parseLong(tokens[11]);

            l.proto = Integer.parseInt(tokens[8]);

            // Additional field below are not currently used
            // int tos = Integer.parseInt(tokens[14]);
            // int val2 = Integer.parseInt(tokens[15]);
            // int val3 = Integer.parseInt(tokens[16]);
            // int val4 = Integer.parseInt(tokens[17]);
            // int val5 = Integer.parseInt(tokens[18]);
            // int val6 = Integer.parseInt(tokens[19]);
            // int val7 = Integer.parseInt(tokens[20]);
            // int val8 = Integer.parseInt(tokens[21]);

            return l; // The record was sucessfully parsed, return it
        
    }

    private NetFSERecord generateV2(String line, int sensor) {
        try {

            NetflowFlowToolsRecord l = new NetflowFlowToolsRecord();
            l.setInitialString(line);
            l.version = 2;
            l.sensor = sensor;
            String[] tokens = line.split(",");

            l.setSrcIP(Long.parseLong(tokens[0]));
            l.setDstIP(Long.parseLong(tokens[1]));    
            
            l.srcPort = Integer.parseInt(tokens[6]);
            l.dstPort = Integer.parseInt(tokens[7]);
            l.srcPkts = Long.parseLong(tokens[10]);
            l.srcBytes = Long.parseLong(tokens[8]);

            l.proto = Integer.parseInt(tokens[5]);

            Timestamp ts = null;
            try {
                ts = Timestamp.valueOf(tokens[9]);
            } catch (Exception e) {
                // try to see if timestamp is YYYYMMDDHHMMSS
                String temp = tokens[9].substring(0, 4) + "-" + tokens[9].substring(4, 6) + "-"
                        + tokens[9].substring(6, 8) + " " + tokens[9].substring(8, 10) + ":"
                        + tokens[9].substring(10, 12) + ":" + tokens[9].substring(12);
                try {
                    ts = Timestamp.valueOf(temp);
                } catch (Exception e2) {
                    ts = new Timestamp(System.currentTimeMillis());
                }
            }

            l.setStartTS(ts);

            l.tos = Integer.parseInt(tokens[13]);
            l.tcpFlags = Integer.parseInt(tokens[14]);

            return l; // The record was sucessfully parsed, return it
        } catch (Exception E) {
            E.printStackTrace();
        }
        return null; // Return null if there is an error in parsing
    }

    public String getCreateFieldTableSQL(String table) {
        StringBuffer temp = new StringBuffer("create table " + table + " (ID bigint, ");
        temp.append("srcip inet,");
        temp.append("srcport int,");
        temp.append("dstip inet,");
        temp.append("dstport int,");
        temp.append("bytes bigint,");
        temp.append("pkts bigint,");
        temp.append("router bigint,");
        temp.append("protocol int,");
        temp.append("startts timestamp,");
        temp.append("endts timestamp");
        temp.append(")");
        return temp.toString();
    }

    public String getCreateFieldTableSQL_MySQL(String table) {
        StringBuffer temp = new StringBuffer("create table " + table + " (ID bigint, ");
        temp.append("srcip bigint,");
        temp.append("srcport int,");
        temp.append("dstip bigint,");
        temp.append("dstport int,");
        temp.append("bytes bigint,");
        temp.append("pkts bigint,");
        temp.append("router bigint,");
        temp.append("protocol int,");
        temp.append("startts datetime,");
        temp.append("endts datetime");
        temp.append(")");
        return temp.toString();
    }
    
    public long getDstIP() {
        return dstIP;
    }

    public int getDstPort() {
        return dstPort;
    }
    
    public Timestamp getEndTS() {
        return getStartTS();
    }

    public FlexRecord getFlexRecord() {
        FlexRecord temp = new FlexRecord();
        temp.values = new String[9];
        int idx = -1;
        temp.values[++idx] = this.getStartTS().toString();
        if (this.getEndTS() != null)
            temp.values[++idx] = this.getEndTS().toString();
        else
            temp.values[++idx] = "";
        temp.values[++idx] = this.getSrcAddr();
        temp.values[++idx] = this.srcPort + "";
        temp.values[++idx] = this.srcPkts + "";
        temp.values[++idx] = this.srcBytes + "";
        temp.values[++idx] = this.dstAddr;
        temp.values[++idx] = this.dstPort + "";
        temp.values[++idx] = this.proto + "";
        return temp;
    }
    
    public FlexRecordField[] getFlexRecordFields() {
        FlexRecordField[] temp = new FlexRecordField[9];
        int idx = -1;
        temp[++idx] = new FlexRecordField("Start Time", "startts", FlexRecordField.TYPE_STRING,
                FlexRecordField.SUB_TYPE_TIMESTAMP);
        temp[++idx] = new FlexRecordField("Stop Time", "endts", FlexRecordField.TYPE_STRING,
                FlexRecordField.SUB_TYPE_TIMESTAMP);
        temp[++idx] = new FlexRecordField("Src IP", "srcip", FlexRecordField.TYPE_STRING,
                FlexRecordField.SUB_TYPE_IP_ADDR);
        temp[++idx] = new FlexRecordField("Src Port", "srcport", FlexRecordField.TYPE_INT,
                FlexRecordField.SUB_TYPE_PORT);
        temp[++idx] = new FlexRecordField("Src Pkts", "pkts", FlexRecordField.TYPE_LONG,
                FlexRecordField.SUB_TYPE_NONE);
        temp[++idx] = new FlexRecordField("Src Bytes", "bytes", FlexRecordField.TYPE_LONG,
                FlexRecordField.SUB_TYPE_NONE);
        temp[++idx] = new FlexRecordField("Dst IP", "dstip", FlexRecordField.TYPE_STRING,
                FlexRecordField.SUB_TYPE_IP_ADDR);
        temp[++idx] = new FlexRecordField("Dst Port", "dstport", FlexRecordField.TYPE_INT,
                FlexRecordField.SUB_TYPE_PORT);
        temp[++idx] = new FlexRecordField("Protocol", "protocol", FlexRecordField.TYPE_STRING,
                FlexRecordField.SUB_TYPE_NONE);
        return temp;
    }
    
    public String getInsertFieldTableSQL(int id, String table) {
        StringBuffer temp = new StringBuffer("insert into " + table + " values (" + id + ",'");
        temp.append(this.getSrcAddr()+ "',");
        temp.append(srcPort + ",'");
        temp.append(this.dstAddr + "',");
        temp.append(dstPort + ",");
        temp.append(srcBytes + ",");
        temp.append(srcPkts + ",");
        temp.append(Long.parseLong(NetFSEUtil.convertIPtoHex(this.router), 16) + ",");
        temp.append(proto + ",");
        temp.append("'" + this.getStartTS() + "',");
        temp.append("'" + this.getEndTS() + "'");
        temp.append(")");
        return temp.toString();
    }
    
    public String getInsertFieldTableSQL_MySQL(int id, String table) {
        StringBuffer temp = new StringBuffer("insert into " + table + " values (" + id + ",");
        temp.append(Long.parseLong(NetFSEUtil.convertIPtoHex(this.getSrcAddr()), 16) + ",");
        temp.append(srcPort + ",");
        temp.append(Long.parseLong(NetFSEUtil.convertIPtoHex(this.dstAddr), 16) + ",");
        temp.append(dstPort + ",");
        temp.append(srcBytes + ",");
        temp.append(srcPkts + ",");
        temp.append(Long.parseLong(NetFSEUtil.convertIPtoHex(this.router), 16) + ",");
        temp.append(proto + ",");
        temp.append("'" + this.getStartTS() + "',");
        temp.append("'" + this.getEndTS() + "'");
        temp.append(")");
        return temp.toString();
    }
    
    public int getProtocol() {
        return this.proto;
    }
    
    public String toString() {
        return toCSV();
    }
    
}
